package com.tulingxueyuan.mall.modules.oms.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.db.sql.Order;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tulingxueyuan.mall.common.exception.ApiException;
import com.tulingxueyuan.mall.common.service.RedisService;
import com.tulingxueyuan.mall.dto.CartItemStorkDto;
import com.tulingxueyuan.mall.dto.ConfimOrderDto;
import com.tulingxueyuan.mall.dto.OrderParamDto;
import com.tulingxueyuan.mall.modules.oms.mapper.OmsOrderMapper;
import com.tulingxueyuan.mall.modules.oms.model.OmsCartItem;
import com.tulingxueyuan.mall.modules.oms.model.OmsOrder;
import com.tulingxueyuan.mall.modules.oms.model.OmsOrderItem;
import com.tulingxueyuan.mall.modules.oms.model.OmsOrderSetting;
import com.tulingxueyuan.mall.modules.oms.service.OmsCartItemService;
import com.tulingxueyuan.mall.modules.oms.service.OmsOrderItemService;
import com.tulingxueyuan.mall.modules.oms.service.OmsOrderService;
import com.tulingxueyuan.mall.modules.oms.service.OmsOrderSettingService;
import com.tulingxueyuan.mall.modules.pms.model.PmsProduct;
import com.tulingxueyuan.mall.modules.pms.model.PmsSkuStock;
import com.tulingxueyuan.mall.modules.pms.service.PmsProductService;
import com.tulingxueyuan.mall.modules.pms.service.PmsSkuStockService;
import com.tulingxueyuan.mall.modules.ums.model.UmsMember;
import com.tulingxueyuan.mall.modules.ums.model.UmsMemberReceiveAddress;
import com.tulingxueyuan.mall.modules.ums.service.UmsMemberReceiveAddressService;
import com.tulingxueyuan.mall.modules.ums.service.UmsMemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author SiXiaoLong
 * @since 2022-10-21
 */
@Service
@Slf4j
public class OmsOrderServiceImpl extends ServiceImpl<OmsOrderMapper, OmsOrder> implements OmsOrderService {
    private static final String REDIS_KEY_PREFIX_ORDER_ID = "order_id";
    @Autowired
    private UmsMemberService memberService;
    @Autowired
    private OmsCartItemService cartItemService;
    @Autowired
    private PmsSkuStockService skuStockService;
    @Autowired
    private PmsProductService productService;
    @Autowired
    private UmsMemberReceiveAddressService memberReceiveAddressService;
    @Autowired
    RedisService redisService;
    @Autowired
    OmsOrderItemService orderItemService;
    @Autowired
    OmsOrderSettingService orderSettingService;
    /**
     * 生成订单（下单）
     * 1:判断库存（没有库存直接提示）
     * 2：保存订单主表oms_order信息  订单号
     * 3：保存订单详情表oms_order_item 购物车转移
     * 4：锁定库存   如果用户超过10分钟没有支付则恢复库存
     * 5：删除对应购物车
     */
    @Override
    @Transactional
    public OmsOrder generateOrder(OrderParamDto orderParamDto) {
        UmsMember umsMember = memberService.getCurrentMember();
            if (orderParamDto.getSkuId()!=null){
    //            判断库存
                PmsSkuStock skuStock = skuStockService.getById(orderParamDto.getSkuId());
                if(skuStock.getStock() - skuStock.getLockStock() < 1){
                    throw new ApiException("库存不足以购买");
                }
    //           2 保存订单主表oms_order信息  订单号
                OmsOrder omsOrder = createOrder(orderParamDto,umsMember,skuStock);
                this.save(omsOrder);
    //            3：保存订单详情表oms_order_item
                OmsOrderItem omsOrderItem =createOrderItem(omsOrder,skuStock);
                orderItemService.save(omsOrderItem);
    //            4:锁定库存
                LambdaUpdateWrapper<PmsSkuStock> luw = new LambdaUpdateWrapper<>();
                luw.setSql("lock_stock=lock_stock+"+1);
                luw.eq(PmsSkuStock::getId,skuStock.getId());
                skuStockService.update(luw);
                return omsOrder;
            }
//        1:判断库存（没有库存直接提示）

        LambdaQueryWrapper<OmsCartItem> lqw = new LambdaQueryWrapper<>();
//      根据id  获取购物车信息
        lqw.eq(OmsCartItem::getMemberId,umsMember.getId());
        lqw.in(OmsCartItem::getId,orderParamDto.getItemIds());
        List<OmsCartItem> omsCartItemList = cartItemService.list(lqw);

//        获取库存不足的名称
        for (OmsCartItem omsCartItem : omsCartItemList) {
            Long productSkuId = omsCartItem.getProductSkuId();
            PmsSkuStock skuStock = skuStockService.getById(productSkuId);
            if(skuStock.getStock() - skuStock.getLockStock() < omsCartItem.getQuantity()){
                throw new ApiException("当前购物车的商品"+omsCartItem.getProductName()+"库存不足以购买");
            }
        }
//        2:保存订单主表oms_order信息  订单号
        OmsOrder omsOrder = newOrder(orderParamDto,umsMember,omsCartItemList);
        this.save(omsOrder);
//        3：保存订单详情表oms_order_item 购物车转移
        List<OmsOrderItem> list = newOrderItems(omsOrder,omsCartItemList);
        orderItemService.saveBatch(list);
//        4:锁定库存
        lockStock(omsCartItemList);
//        5:删除对应购物车
        removeCartItem(omsCartItemList);
        return omsOrder;
    }

//     直接购买的生成订单详情
    private OmsOrderItem createOrderItem(OmsOrder omsOrder, PmsSkuStock skuStock) {
        LambdaQueryWrapper<PmsProduct> lqw = new LambdaQueryWrapper<>();
        lqw.eq(PmsProduct::getId,skuStock.getProductId());
        PmsProduct product = productService.getOne(lqw);
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            omsOrderItem.setOrderId(omsOrder.getId());
            omsOrderItem.setOrderSn(omsOrder.getOrderSn());
            omsOrderItem.setProductId(skuStock.getProductId());
            omsOrderItem.setProductPic(product.getPic());
            omsOrderItem.setProductName(product.getName());
            omsOrderItem.setProductBrand(product.getBrandName());
            omsOrderItem.setProductSn(product.getProductSn());
            omsOrderItem.setProductPrice(skuStock.getPrice());
            omsOrderItem.setProductQuantity(1);
            omsOrderItem.setProductSkuId(skuStock.getId());
            omsOrderItem.setProductSkuCode(skuStock.getSkuCode());
            omsOrderItem.setProductCategoryId(product.getProductCategoryId());
            omsOrderItem.setSp1(skuStock.getSp1());
            omsOrderItem.setSp2(skuStock.getSp2());
            omsOrderItem.setSp3(skuStock.getSp3());
        return omsOrderItem;
    }

    //  直接购买的生成订单
    private OmsOrder createOrder(OrderParamDto orderParamDto, UmsMember umsMember,PmsSkuStock skuStock) {
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setCreateTime(new Date());
        omsOrder.setModifyTime(new Date());
        omsOrder.setMemberId(umsMember.getId());
        omsOrder.setMemberUsername(umsMember.getUsername());
//      计算价格
        ConfimOrderDto confimOrderDto = new ConfimOrderDto();
//      计算价格
        omsOrder.setTotalAmount(skuStock.getPrice());
        omsOrder.setPayAmount(skuStock.getPrice().add(new BigDecimal(10)));
        omsOrder.setFreightAmount(new BigDecimal(10));
//        订单来源
        omsOrder.setSourceType(1);
        omsOrder.setStatus(0);
        omsOrder.setOrderType(0);  //订单类型  0->正常订单  1->秒杀订单
        omsOrder.setAutoConfirmDay(15);  //自动确认收货时间
//        地址
        LambdaQueryWrapper<UmsMemberReceiveAddress> lqw = new LambdaQueryWrapper<>();
        lqw.eq(UmsMemberReceiveAddress::getMemberId,umsMember.getId());
        lqw.eq(UmsMemberReceiveAddress::getId,orderParamDto.getMemberReceiveAddressId());
        UmsMemberReceiveAddress receiveAddress = memberReceiveAddressService.getOne(lqw);
        omsOrder.setReceiverName(receiveAddress.getName());
        omsOrder.setReceiverPhone(receiveAddress.getPhoneNumber());
        omsOrder.setReceiverPostCode(receiveAddress.getPostCode());
        omsOrder.setReceiverProvince(receiveAddress.getProvince());
        omsOrder.setReceiverCity(receiveAddress.getCity());
        omsOrder.setReceiverRegion(receiveAddress.getRegion());
        omsOrder.setReceiverDetailAddress(receiveAddress.getDetailAddress());
        omsOrder.setConfirmStatus(0);
        omsOrder.setOrderSn(getOrderSn(omsOrder));
        return omsOrder;
    }

    //    订单超时关闭并返回已锁定库存
    @Override
    @Transactional
    public void cancelOverTimeOrder() {
//        获取规定的时间
        OmsOrderSetting orderSetting = orderSettingService.getById(1);
        Integer normalOrderOvertime = orderSetting.getNormalOrderOvertime();
//        获取超过规定时间未支付的订单
//        获取指定时间之前的时间点   偏移10分钟
        DateTime offset = DateUtil.offset(new Date(), DateField.MINUTE, -normalOrderOvertime);
        LambdaQueryWrapper<OmsOrder> lqw = new LambdaQueryWrapper<>();
        lqw.eq(OmsOrder::getStatus,0);  //未支付
        lqw.le(OmsOrder::getCreateTime,offset);  //大于等于 规定的时间 就是超时
        List<OmsOrder> omsOrderList = this.list(lqw);  //所有超时未支付的订单
        if (CollectionUtils.isEmpty(omsOrderList)){
            log.warn("暂无超时订单");
            return;
        }
//        改变订单状态为关闭
//        获取订单集合id
        List<Long> orderIds = new ArrayList<>();
        omsOrderList.forEach(e->{
            e.setStatus(4);
            e.setModifyTime(new Date());
            orderIds.add(e.getId());
        });
        this.updateBatchById(omsOrderList);
//        归还锁定库存
//          获取订单详情
        LambdaQueryWrapper<OmsOrderItem> lqw2 = new LambdaQueryWrapper<>();
        lqw2.in(OmsOrderItem::getOrderId,orderIds);
        List<OmsOrderItem> orderItemList = orderItemService.list(lqw2);
//        循环归还库存
        for (OmsOrderItem orderItem : orderItemList) {
//            需要归还的数量
            Integer quantity = orderItem.getProductQuantity();
//            获取skuid
            Long skuId = orderItem.getProductSkuId();
//            更新lock_stock
            LambdaUpdateWrapper<PmsSkuStock> luw = new LambdaUpdateWrapper<>();
            luw.eq(PmsSkuStock::getId,skuId);
            luw.setSql("lock_stock=lock_stock-"+quantity);
            skuStockService.update(luw);
        }

    }

    /**
     * 删除对应购物车
     */
    private void removeCartItem(List<OmsCartItem> omsCartItemList) {
        List<Long> ids = new ArrayList<>();
        for (OmsCartItem omsCartItem : omsCartItemList) {
            ids.add(omsCartItem.getId());
        }
        cartItemService.removeByIds(ids);
    }

    /**
     *  锁定库存  把当前购买的数累加到sku lock_stock
     */
    private void lockStock(List<OmsCartItem> omsCartItemList) {
        for (OmsCartItem omsCartItem : omsCartItemList) {
            LambdaUpdateWrapper<PmsSkuStock> luw = new LambdaUpdateWrapper<>();
            luw.setSql("lock_stock=lock_stock+"+omsCartItem.getQuantity());
            luw.eq(PmsSkuStock::getId,omsCartItem.getProductSkuId());
            skuStockService.update(luw);
        }
    }

    //      购物车和订单编号 组成订单详情
    private List<OmsOrderItem> newOrderItems(OmsOrder omsOrder, List<OmsCartItem> omsCartItemList) {
        List<OmsOrderItem> list = new ArrayList<>();
        for (OmsCartItem omsCartItem : omsCartItemList) {
            OmsOrderItem omsOrderItem = new OmsOrderItem();
            omsOrderItem.setOrderId(omsOrder.getId());
            omsOrderItem.setOrderSn(omsOrder.getOrderSn());
            omsOrderItem.setProductId(omsCartItem.getProductId());
            omsOrderItem.setProductPic(omsCartItem.getProductPic());
            omsOrderItem.setProductName(omsCartItem.getProductName());
            omsOrderItem.setProductBrand(omsCartItem.getProductBrand());
            omsOrderItem.setProductSn(omsCartItem.getProductSn());
            omsOrderItem.setProductPrice(omsCartItem.getPrice());
            omsOrderItem.setProductQuantity(omsCartItem.getQuantity());
            omsOrderItem.setProductSkuId(omsCartItem.getProductSkuId());
            omsOrderItem.setProductSkuCode(omsCartItem.getProductSkuCode());
            omsOrderItem.setProductCategoryId(omsCartItem.getProductCategoryId());
            omsOrderItem.setSp1(omsCartItem.getSp1());
            omsOrderItem.setSp2(omsCartItem.getSp2());
            omsOrderItem.setSp3(omsCartItem.getSp3());
            list.add(omsOrderItem);
        }
        return list;
    }

    private OmsOrder newOrder(OrderParamDto orderParamDto,UmsMember umsMember,List<OmsCartItem> omsCartItemList){
        OmsOrder omsOrder = new OmsOrder();
        omsOrder.setCreateTime(new Date());
        omsOrder.setModifyTime(new Date());
        omsOrder.setMemberId(umsMember.getId());
        omsOrder.setMemberUsername(umsMember.getUsername());
//      计算价格
        ConfimOrderDto confimOrderDto = new ConfimOrderDto();
//        购物车集合
        confimOrderDto.setCartItemList(omsCartItemList);
//      计算价格
        calcCatAmount(confimOrderDto);
        omsOrder.setTotalAmount(confimOrderDto.getPriceTotal());
        omsOrder.setPayAmount(confimOrderDto.getPayAmount());
        omsOrder.setFreightAmount(confimOrderDto.getFreightAmount());
//        订单来源
        omsOrder.setSourceType(1);
        omsOrder.setStatus(0);
        omsOrder.setOrderType(0);  //订单类型  0->正常订单  1->秒杀订单
        omsOrder.setAutoConfirmDay(15);  //自动确认收货时间
//        地址
        LambdaQueryWrapper<UmsMemberReceiveAddress> lqw = new LambdaQueryWrapper<>();
        lqw.eq(UmsMemberReceiveAddress::getMemberId,umsMember.getId());
        lqw.eq(UmsMemberReceiveAddress::getId,orderParamDto.getMemberReceiveAddressId());
        UmsMemberReceiveAddress receiveAddress = memberReceiveAddressService.getOne(lqw);
        omsOrder.setReceiverName(receiveAddress.getName());
        omsOrder.setReceiverPhone(receiveAddress.getPhoneNumber());
        omsOrder.setReceiverPostCode(receiveAddress.getPostCode());
        omsOrder.setReceiverProvince(receiveAddress.getProvince());
        omsOrder.setReceiverCity(receiveAddress.getCity());
        omsOrder.setReceiverRegion(receiveAddress.getRegion());
        omsOrder.setReceiverDetailAddress(receiveAddress.getDetailAddress());
        omsOrder.setConfirmStatus(0);
        omsOrder.setOrderSn(getOrderSn(omsOrder));
        return omsOrder;
    }
//    生成订单id
    public String getOrderSn(OmsOrder omsOrder){
        StringBuilder sb = new StringBuilder();
//        前八位为日期
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String yyyyMMDD = format.format(new Date());
        sb.append(yyyyMMDD);
//        中间两位为平台
        String sourceTyp = String.format("%02d", omsOrder.getSourceType());
        sb.append(sourceTyp);
//        6位以上自增id
        String key = REDIS_KEY_PREFIX_ORDER_ID+yyyyMMDD;
        Long incr = redisService.incr(key, 1);
//        如果小于6为补零   超过六位就不补了
        if (incr.toString().length()<=6) {
           sb.append(String.format("%06d", redisService.incr(key, 1))) ;
        }else {
            sb.append(incr);
        }
        return sb.toString();
    }
//    计算价格
    public void calcCatAmount(ConfimOrderDto confimOrderDto){
//        计算商品数量
        Integer productTotal=0;
//        总价
        BigDecimal priceTotal=new BigDecimal(0);
//        运费
        BigDecimal freightAmount = new BigDecimal(0);
//        BigDecimal payAmount=new BigDecimal(0);
        for (OmsCartItem cartItem : confimOrderDto.getCartItemList()) {
//            计算商品数量
            productTotal += cartItem.getQuantity();
//         总价   BigDecimal类型不能喝integer类型直接计算  需要转化成BigDecimal对象 之后调用对应方法计算
            priceTotal = priceTotal.add(cartItem.getPrice().multiply(new BigDecimal(cartItem.getQuantity())));
            PmsProduct product = productService.getById(cartItem.getProductId());
            String serviceIds = product.getServiceIds();
//            拿到对应的1,2,3  3是是否包邮
            String[] strings = serviceIds.split(",");
            if (strings.length>0){
//                判断是否包邮
                if(!ArrayUtil.containsAny(strings,3)){
//                    不包邮的话累加10元
                    freightAmount = freightAmount.add(new BigDecimal(10).multiply(new BigDecimal(cartItem.getQuantity())));
                }
            }
        }
        confimOrderDto.setProductTotal(productTotal);
        confimOrderDto.setFreightAmount(freightAmount);
        confimOrderDto.setPriceTotal(priceTotal);
        confimOrderDto.setPayAmount(priceTotal.add(freightAmount));
    }
}
